import { 
  AmbientLight,
  AnimationAction,
  AnimationMixer,
  BoxGeometry,
  Clock,
  Color,
  IcosahedronGeometry,
  Mesh,
  MeshLambertMaterial,
  MeshStandardMaterial,
  PerspectiveCamera,
  PlaneGeometry,
  PointLight,
  Scene, 
  SphereGeometry, 
  SpotLight, 
  SpotLightHelper, 
  TextureLoader, 
  WebGLRenderer
} from "three";
import stats from '../utils/stats';
// 调用
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { GUI } from 'dat.gui';

let scene = new Scene();
let renderer = setRenderer();
let camera = setCamera();

setLight();
let sphereMesh = init();

const trackballControls = new OrbitControls(camera, renderer.domElement);
// 调整场景位置
trackballControls.target.set(0, 3, 0);


let invert = 1;
let phase = 0;
function render() {
  stats.update();
  trackballControls.update();

  // 小球动画
  if (phase > 2 * Math.PI) {
    invert = invert * -1;
    phase -= 2 * Math.PI;
  } else {
    phase += 0.02;
  }

  sphereMesh.position.z = +(21 * Math.sin(phase));
  sphereMesh.position.x = -14 + (14 * Math.cos(phase));

  if (invert < 0) {
    let pivot = 0;
    sphereMesh.position.x = (invert * (sphereMesh.position.x - pivot)) + pivot;
  }

  requestAnimationFrame(render);
  renderer.render(scene, camera);
}
render();

function setRenderer() {
  const renderer = new WebGLRenderer({ antialias: true });
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 支持阴影生成 
  renderer.shadowMap.enabled = true;
  document.body.appendChild(renderer.domElement);

  return renderer
}

function setCamera(): PerspectiveCamera {
  let camera = new PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);
  camera.position.set(0, 20, 40);
  scene.add( camera );

  return camera;
}

// 灯光设置
function setLight() {
  scene.add(new AmbientLight(0x444444));
  scene.add(new AmbientLight(0x343434));
  
  let spotLight = new SpotLight(0xffffff);
  spotLight.position.set(-10, 30, 40);
  spotLight.shadow.mapSize.width = 2048;
  spotLight.shadow.mapSize.height = 2048;
  spotLight.shadow.camera.fov = 15;
  spotLight.decay =2;
  spotLight.penumbra = 0.05;
  spotLight.castShadow = true;

  scene.add(spotLight);
  // scene.add(new SpotLightHelper(spotLight));
}

/** 功能区 */
function init() {
  let textureLoader = new TextureLoader();

  let planeGeom = new PlaneGeometry(60, 40, 1, 1);
  let planeMate = new MeshLambertMaterial({
    color: 0xffffff,
    map: textureLoader.load('/textures/general/floor-wood.jpg')
  });
  const plane = new Mesh(planeGeom, planeMate);
  plane.receiveShadow = true;
  plane.rotation.x = -Math.PI / 2;
  scene.add(plane);

  let color = new Color(0xff5808);
  let sphereLight = new SphereGeometry(0.2);
  let sphereMater = new MeshStandardMaterial({color});
  let sphereMesh = new Mesh(sphereLight, sphereMater);
  sphereMesh.add(new PointLight(color));
  sphereMesh.position.y = 5;
  scene.add(sphereMesh);

  // 添加矩形
  let cubeGeom = new BoxGeometry(10, 10, 10);
  let cubeMate = new MeshStandardMaterial({
    metalness: 0.2,
    roughness: 0.7,
    map: textureLoader.load('/textures/general/plaster.jpg')
  });
  let cubeMesh = new Mesh(cubeGeom, cubeMate);
  cubeMesh.position.x = -10;
  cubeMesh.position.y = 5;
  cubeMesh.castShadow = true;
  scene.add(cubeMesh);

  // 添加矩形
  let cubeGeom2 = new BoxGeometry(10, 10, 10);
  let cubeMate2 = new MeshStandardMaterial({
    metalness: 0.2,
    roughness: 0.07,
    map: textureLoader.load('/textures/general/plaster.jpg')
  });
  let normalMap = cubeMate2.clone();
  
  // 法向贴图
  normalMap.normalMap = textureLoader.load('/textures/general/plaster-normal.jpg')
  let cubeMesh2 = new Mesh(cubeGeom2, normalMap);
  cubeMesh2.position.x = 10;
  cubeMesh2.position.y = 5;
  cubeMesh2.castShadow = true;
  scene.add(cubeMesh2);

  addGUI(normalMap);

  return sphereMesh
}


function addGUI(bump: MeshStandardMaterial): void {
  const controls = {
    normalScaleX: 1,
    normalScaleY: 1
  }
  const gui = new GUI();  

  gui.add(controls, 'normalScaleX', -3, 3, 0.001).onChange(val => {
    bump.normalScale.set(val, controls.normalScaleY);
  });
  gui.add(controls, 'normalScaleY', -3, 3, 0.001).onChange(val => {
    bump.normalScale.set(controls.normalScaleX, val);
  });
}